package com.googlecode.maurersmarbles;

import android.graphics.Color;
import android.graphics.Point;

import com.googlecode.maurersmarbles.framework.Graphics;

public abstract class Board {

	/**
	 * The size of the grid that makes up the spaces on the board.
	 */
	protected static final int GRID_SIZE = 15;
	/**
	 * The size of each grid cell (width and height).
	 */
	protected double gridCellSize;
	/**
	 * The scale factor used to calculate the size of a marble.
	 */
	protected double marbleScaleFactor = 0.75;
	/**
	 * The scale factor used to calculate the playable area size.
	 */
	protected double paddingScaleFactor = 0.07;
	/**
	 * The scale factor used to calculate the size of a space.
	 */
	protected double spaceScaleFactor = 0.6;
	/**
	 * The start x location of the playable area.
	 */
	protected int innerStartX;
	/**
	 * The start y location of the playable area.
	 */
	protected int innerStartY;
	/**
	 * The size of the playable area.
	 */
	protected int innerSize;
	/**
	 * The size of a marble on the board.
	 */
	protected int marbleSize;
	/**
	 * The size of the board (width and height).
	 */
	protected final int size;
	/**
	 * The size of a space on the board.
	 */
	protected int spaceSize;	
	/**
	 * The x/y location of the board.
	 */
	protected final Point startXY;

	/**
	 * Creates a new Board.
	 * 
	 * @param startXY the x location of the board
	 * @param size the size of the board (width and height)
	 */
	public Board(Point startXY, int size) {
		
		this.startXY = startXY;
		this.size = size;
		
		initBoard();
		
	}
	
	/**
	 * Initializes the board.
	 */
	public void initBoard() {
		
		int innerOffset = (int) ((paddingScaleFactor / 2.0) * size);
		innerStartX = startXY.x + innerOffset;
		innerStartY = startXY.y + innerOffset;
		innerSize = (int) (size - (innerOffset * 2));
		
		gridCellSize = innerSize / (float) (GRID_SIZE);
		
		spaceSize = (int)(gridCellSize * spaceScaleFactor);
		marbleSize = (int)(gridCellSize * marbleScaleFactor);
		
	}
	
	/**
	 * Returns the x/y for the upper left corner of the marble.
	 * @param row the row in the grid
	 * @param col the column in the grid
	 * @param size the size of the marble
	 * @return the x/y for the upper left corner of the marble
	 */
	public Point getMarbleXY(double row, double col, double size) {
		double offset = (gridCellSize - size) / 2.0;		
		int x = (int)(innerStartX + (col * gridCellSize) + offset);
		int y = (int)(innerStartY + (row * gridCellSize) + offset);
		return new Point(x, y);
	}
	
	/**
	 * Returns the x/y for the upper left corner of the space.
	 * @param row the row in the grid
	 * @param col the column in the grid
	 * @return the x/y for the upper left corner of the space
	 */
	public Point getSpaceXY(int row, int col) {
		double offset = (gridCellSize - spaceSize) / 2.0;		
		int x = (int)(innerStartX + (col * gridCellSize) + offset);
		int y = (int)(innerStartY + (row * gridCellSize) + offset);
		return new Point(x, y);
	}
	
	/**
	 * Draws the board based on the current state of the game.
	 * 
	 * @param g the graphics to draw on
	 * @param gameState the current game state
	 */
	public void draw(Graphics g, GameState gameState) {

		/**
		 * Draw the board.
		 */
		drawBoard(g, startXY, size);

		/**
		 * Draw the empty spaces on the board.
		 */
		for(int i = -2; i <= 2; i++) {
			for(int j = 0; j <= ((i == -2 || i == 2) ? 5 : 0); j++) {
				drawEmptySpace(g, getSpaceXY(7 + i, 0 + j), spaceSize);
				drawEmptySpace(g, getSpaceXY(0 + j, 7 + i), spaceSize);
				drawEmptySpace(g, getSpaceXY(7 + i, 14 - j), spaceSize);
				drawEmptySpace(g, getSpaceXY(14 - j, 7 - i), spaceSize);
			}
		}	

		/**
		 * Draw the safe spaces on the board.
		 */
		drawSafeSpace(g, getSpaceXY(14, 5), spaceSize, 0);
		drawSafeSpace(g, getSpaceXY(5, 0), spaceSize, 1);
		drawSafeSpace(g, getSpaceXY(0, 9), spaceSize, 2);
		drawSafeSpace(g, getSpaceXY(9, 14), spaceSize, 3);
		
		/**
		 * Draw the home spaces on the board.
		 */
		for (int i = 1; i <= 4; i++) {
			drawHomeSpace(g, getSpaceXY(14 - i, 7), spaceSize, 0);
			drawHomeSpace(g, getSpaceXY(7, 0 + i), spaceSize, 1);
			drawHomeSpace(g, getSpaceXY(0 + i, 7), spaceSize, 2);
			drawHomeSpace(g, getSpaceXY(7, 14 - i), spaceSize, 3);
		}

		/**
		 * Draw the start spaces on the board.
		 */
		for(int i = 0; i <= 2; i += 2) {
			for(int j = 0; j <= 2; j += 2) {
				drawStartSpace(g, getSpaceXY(11 + i, 1 + j), spaceSize, 0);
				drawStartSpace(g, getSpaceXY(1 + i, 1 + j), spaceSize, 1);
				drawStartSpace(g, getSpaceXY(1 + i, 11 + j), spaceSize, 2);
				drawStartSpace(g, getSpaceXY(11 + i, 11 + j), spaceSize, 3);
			}
		}
		
		/**
		 * Draw the marbles on the board.
		 */
		Byte[][] marbles = gameState.getMarbles();
		for(int i = 0; i < GameLogic.NUMBER_OF_PLAYERS; i++) {
			for(int j = 0; j < GameLogic.MARBLES_PER_PLAYER; j++) {
				Point cell = GameLogic.getCellForIndex(marbles[i][j]);
				drawMarble(g, getMarbleXY(cell.y, cell.x, marbleSize), marbleSize, i);
			}
		}
		
//		for(int i = 0; i <= GRID_SIZE; i++) {
//			g.drawLine(innerStartX, (int)(innerStartY + (gridCellSize * i)), innerStartX + innerSize, (int)(innerStartY + (gridCellSize * i)), Color.BLACK);
//			g.drawLine((int)(innerStartX + (gridCellSize * i)), innerStartY, (int)(innerStartX + (gridCellSize * i)), innerStartY + innerSize, Color.BLACK);
//		}
		
	}
	
	public abstract void drawBoard(Graphics g, Point point, int size);

	public abstract void drawEmptySpace(Graphics g, Point point, int size);

	public abstract void drawHomeSpace(Graphics g, Point point, int size,
			int player);

	public abstract void drawMarble(Graphics g, Point point, int size,
			int player);

	public abstract void drawSafeSpace(Graphics g, Point point, int size,
			int player);

	public abstract void drawStartSpace(Graphics g, Point point, int size,
			int player);
	
}
